import { ConstraintType, CurveType } from '@amcax/base';
import { AnnotationType } from '../dimension/types';
import { dimRender } from './render';
import { DimInfo, formatDim, GroupsType, lineTramsformPoint } from './type';
const mutualExclusion = [
  AnnotationType.DistanceAnno,
  AnnotationType.DistanceXAnno,
  AnnotationType.DistanceYAnno,
];
// 默认的muExcDimFlag
const MuExcDimKey = 'hasEqualConDimId';
const fixCons = [
  ConstraintType.Horizontal,
  ConstraintType.Vertical,
  ConstraintType.Fix,
];
const Perpendicular = ConstraintType.Perpendicular;

enum State {
  PENDING = 'pending',
  FINISH = 'finish',
}
export default class IsDriven {
  private isCurveFixed: boolean = false; // 曲线是否被固定 当有约束2（横向）， 3（竖向）， 16（固定）
  // 互斥Array 用于处理角度约束特殊情况
  private isAlwaysPending: boolean = false; // 是否一直处于检测状态
  private curveIsFixs = []; // 存储当前检测是否是互斥的标注
  // -----------------------------------
  static instance: IsDriven; // 单例
  private isExistDim: boolean; // 是否存在标注
  private state: State; // PENDING: 正在检测，FINISH: 检测完成
  private formatDims: string[]; // 存储格式化后的标注数据 （将点线和线线转化成点点去处理）
  private groupsIds: string[] = []; // 存储 curve 的 group的id 用于判断是否检测过 过度约束
  private muExcDimFlag: { [key: string]: boolean[] } = {}; // 存储互斥标注的标志位
  private polygonExtraIds: string[] = []; // 存储多边形的额外标注
  private PolygonCircleIds: string[] = []; // 存储多边形和圆的额外标注
  private PolyCirGroups: GroupsType = null;
  static getInstance(): IsDriven {
    if (!this.instance) {
      this.instance = new IsDriven();
    }
    return this.instance;
  }
  // 对标注进行检测 是否是过约束
  private hasDim(item: DimInfo, groupid?: string | string[]) {
    if (this.isExistDimByKey(item, item.type)) {
      this.finish();
    }
    if (this.isContinue() && mutualExclusion.includes(item.type)) {
      this.checkMuExcDim(item, groupid);
    }
    return this.isExistDim;
  }
  // 检测互斥的标注
  private checkMuExcDim(item: DimInfo, groupid?: string | string[]) {
    const key = dimRender().getMapKey(item);
    if (dimRender().getDimObj()[key] && !this.isAlwaysPending) {
      this.finish();
    } else {
      let flag = false;
      if (!Array.isArray(groupid)) {
        if (this.getFlagsLength(item, groupid)) {
          flag = true;
        }
      } else {
        groupid.forEach((id) => {
          if (this.getFlagsLength(item, id)) {
            flag = true;
          }
        });
      }
      if (flag) {
        this.finish();
        this.curveIsFixs.push(true);
      }
    }
  }
  // 对标注进行检测 用于互斥标注的检测
  private getFlagsLength(item: DimInfo, groupid: string) {
    let flagsLength = 0;
    mutualExclusion.forEach((type) => {
      if (this.isExistDimByKey(item, type)) {
        if (groupid) {
          if (!this.muExcDimFlag[groupid]) {
            this.muExcDimFlag[groupid] = [true];
            flagsLength = 1;
            if (this.isCurveFixed) {
              flagsLength = 2;
            }
          } else {
            this.muExcDimFlag[groupid].push(true);
            flagsLength = 2;
          }
        } else {
          flagsLength += 1;
        }
      }
    });
    return flagsLength === 2; // true: 存在互斥标注
  }
  // 检测标注是否存在
  private isExistDimByKey(item, type) {
    const key = dimRender().getMapKey({ objects: item.objects, type });
    return this.formatDims.includes(key) || dimRender().getDimObj()[key];
  }
  // 判断是否可以继续检测
  private isContinue() {
    return this.state === State.PENDING || this.isAlwaysPending;
  }
  // 将点线和线线标注转换成点点标注
  public setRectDims() {
    this.formatDims = formatDim();
  }
  // 重置
  private reset() {
    dimRender().getCurrentSketchCurve();
    this.isExistDim = false;
    this.state = State.PENDING;
    this.groupsIds = [];
    this.muExcDimFlag = {};
    this.isAlwaysPending = false;
    this.curveIsFixs = [];
    this.isCurveFixed = false;
    this.polygonExtraIds = [];
    this.PolygonCircleIds = [];
    this.PolyCirGroups = null;
  }
  public isSecondaryDim({ objects, type, curveIds }: DimInfo) {
    this.reset();
    if (this.hasDim({ objects, type })) {
      return true;
    }
    this.isAlwaysPending = type === AnnotationType.AngleAnno;
    this.hasEqualConDim(curveIds, type);
    if (this.isContinue()) {
      if (this.curveIsFixed(objects, [ConstraintType.Fix])) {
        return true;
      } else {
        this.isExist({ objects, type });
      }
    }
    return this.isExistDim;
  }
  private hasEqualConDim(curveIds, type?: AnnotationType) {
    delete this.muExcDimFlag[MuExcDimKey];
    if (
      curveIds?.length === 1 &&
      (mutualExclusion.includes(type) || type === AnnotationType.RadiusAnno)
    ) {
      const res = this.isCheckFixedById(curveIds[0]);
      if (mutualExclusion.includes(type)) {
        this.checkCurveExcDim(curveIds, type, res);
      }
      // 角度标注的特殊情况
    } else if (type === AnnotationType.AngleAnno) {
      const { groupidsMap, pointIds } = getGroupsByPointIds(curveIds);
      const groupIds = Object.keys(groupidsMap);
      if (groupIds.length > 0) {
        const groupT = Object.values(groupidsMap)[0];
        if (groupT[0][1].includes('Rect')) {
          if (groupIds.length === 1) {
            const flag = this.checkSameConAngleDim(groupIds); // 检测同一个图形的中是否有过角度约束
            if (flag) {
              return this.finish();
            }
          }
          // 角度标注的特殊情况  即标注为同一个图形的两条线，判断是否有固定、垂直、水平约束
          const flag1 = checkRectFixed(curveIds[0], Perpendicular);
          const flag2 = checkRectFixed(curveIds[1], Perpendicular);
          this.finish(flag1 && flag2);
        } else {
          this.finish();
        }
      } else {
        const curveIsFixs = [];
        curveIds.forEach((id) => {
          const res = this.isCheckFixedById(id);
          const flag =
            this.checkCurveExcDim([id], 2, res) || checkRectFixed(id);
          if (this.curveIsFixed([id]) || flag || this.isCurveFixed === true) {
            curveIsFixs.push(true);
          } else {
            this.isExist({ objects: pointIds[id], type: 2 });
          }
          this.isCurveFixed = false;
        });
        this.finish(curveIsFixs.length + this.curveIsFixs.length >= 2);
        this.isAlwaysPending = false;
      }
    }
  }
  isCheckFixedById(id) {
    const curves = dimRender().getSketMap();
    const group = curves
      .get(id)
      ?.['groups'].find((item) => item.type.includes('Polygon'));
    const temp = [];
    if (group) {
      curves.forEach((item) => {
        const res = item.groups.some(
          (groupItem) => groupItem.groupid === group.groupid,
        );
        if (!res) {
          return;
        }
        if (item.type === 'Line' || item.type === 'Circle') {
          const flag = item.groups.some((groupItem) => groupItem.idx === -1);
          if (!flag) {
            temp.push(item.id);
          } else if (item.type === 'Line') {
            if (this.curveIsFixed([item.id])) {
              this.isCurveFixed = true;
            }
            this.polygonExtraIds = [item.relative[0], item.relative[1]];
          } else {
            this.PolygonCircleIds = [item.id];
            this.PolyCirGroups = item.groups[0];
          }
        }
      });
    }
    return temp;
  }
  // 检测同种相等约束的线是否有互斥标注
  private checkCurveExcDim(
    curveIds: string[],
    type: AnnotationType,
    polygonEdgeIds: string[] = [],
  ) {
    const curves = [];
    mutualExclusion.forEach((i) => {
      if (i !== 2 && this.isExistDimByKey({ objects: curveIds }, i)) {
        curves.push(true);
      }
    });
    const equalArr = dimRender()
      .getEqualConArr()
      .find((item) => item.includes(curveIds[0]));
    equalArr?.forEach((id) => {
      const flag = !!this.isExistDimByKey({ objects: [id] }, 2);
      if (type === 2 && flag && !this.isAlwaysPending) {
        this.finish();
      } else {
        if (flag) {
          curves.push(true);
        }
      }
      if (polygonEdgeIds.includes(id) && this.curveIsFixed([id])) {
        this.isCurveFixed = true;
      }
    });
    if (curves.length >= 2 && !this.isAlwaysPending) {
      this.finish();
    }
    return curves?.length >= 2;
  }
  // 检测是否固有定约束
  public curveIsFixed(objects, fixCon?: ConstraintType[]) {
    let isFixed = true;
    objects.forEach((id) => {
      const curves = dimRender().getSketMap().get(id);
      const flag = curves?.constraints.some((cons) =>
        (fixCon || fixCons).includes(cons.type),
      );
      if (!flag) {
        isFixed = false;
      }
    });
    return isFixed;
  }
  private finish(flag = true) {
    this.state = State.FINISH;
    this.isExistDim = flag;
  }
  private isExist({ objects, type }: DimInfo) {
    if (this.isContinue()) {
      const { pointIds, lineIds } = lineTramsformPoint(objects, type);
      const { groupidsMap: ids } = getGroupsByPointIds(objects);
      const idsArr = Object.keys(ids);
      // 判断是不是点线数量相等且长度为一
      const isPointAndLine = pointIds.length === 1 && lineIds.length === 1;
      // 判断点是否大于线的数量
      const isPointMany = pointIds.length > lineIds.length;
      const item = {
        objects: isPointMany ? pointIds : isPointAndLine ? objects : lineIds,
        type,
      };
      const flag = this.hasDim(item, idsArr.length && idsArr);
      // 正多边形辅助圆特殊处理
      if (this.PolyCirGroups && type === 6) {
        const relativeIdx = getRelativeIdx([], this.PolyCirGroups.type);
        relativeIdx.forEach((item) => {
          this.checkCurveHasDim(this.PolyCirGroups.groupid, item, 2);
        });
      } else if (pointIds.length === 2 && !flag) {
        const groupsInfo = getGroupsByPointIds(pointIds);
        this.handleGroups(groupsInfo, type);
      }
    }
  }
  /**
   * 检 检测同一个图形的中是否有过角度约束
   * @param groupIds 图形的id
   * */

  private checkSameConAngleDim(groupIds) {
    const curves = dimRender().getSketMap();
    const rectLineIds = [];
    curves.forEach((item) => {
      if (
        item?.groups.some((group) => groupIds[0] === group.groupid) &&
        item.type === 'Line'
      ) {
        rectLineIds.push(item.id);
      }
    });
    let flag = false;
    for (let i = 0; i < rectLineIds.length; i++) {
      for (let j = i + 1; j < rectLineIds.length; j++) {
        if (
          this.isExistDimByKey(
            { objects: [rectLineIds[i], rectLineIds[j]] },
            AnnotationType.AngleAnno,
          )
        ) {
          flag = true;
        }
      }
    }
    return flag;
  }
  private handleGroups<T>(
    { groupidsMap }: { groupidsMap: T },
    type: AnnotationType,
  ) {
    Object.keys(groupidsMap).forEach((id) => {
      const group = groupidsMap[id];
      // 判断是否已经存在
      if (this.isContinue() && !this.groupsIds.includes(id)) {
        this.groupsIds.push(id);
        const idx = group.map((item) => item[0]);
        const relativeIdx = getRelativeIdx(idx, group[0][1]);
        if (group[0][1].includes('Polygon')) {
          const ids = [this.PolygonCircleIds, this.polygonExtraIds];
          ids.forEach((its) => {
            if (
              its?.length === 1 &&
              this.isExistDimByKey({ objects: its }, 6)
            ) {
              if (type === 2 || this.isCurveFixed) {
                this.finish();
              } else {
                this.isCurveFixed = true;
              }
            } else {
              this.hasDim({ objects: its, type }, id);
            }
          });
          relativeIdx.forEach((item) => {
            this.checkCurveHasDim(id, item, type);
          });
        } else {
          this.checkCurveHasDim(id, relativeIdx, type);
        }
      }
    });
  }
  // 根据grupid和idxs检测是否有标注
  private checkCurveHasDim(
    groupid: string,
    idxs: number[],
    type?: AnnotationType,
  ) {
    const ids = getCurveIdsByGroupId(groupid, idxs, ['Point']);
    this.hasDim({ objects: ids, type }, groupid);
    const nextInfo = getGroupsByPointIds(ids);
    this.handleGroups(nextInfo, type);
  }
}

export const isDriven = () => {
  return IsDriven.getInstance();
};
function isGroup(item, groupid, idxs) {
  const groupidArr = Array.isArray(groupid) ? groupid : [groupid];
  return item?.groups.some((group) => {
    if (idxs) {
      return groupidArr.includes(group.groupid) && idxs?.includes(group.idx);
    } else {
      return groupidArr.includes(group.groupid);
    }
  });
}
// 根据groupid和idxs获取curve的id
export function getCurveIdsByGroupId(
  groupid: string | string[],
  idxs: number[],
  curveType: CurveType[],
) {
  const ruleGraphIds = [];
  const curves = dimRender().getSketMap();
  curves.forEach((item) => {
    if (curveType.includes(item.type) && isGroup(item, groupid, idxs)) {
      ruleGraphIds.push(item);
    }
  });
  return ruleGraphIds.map((item) => item.id);
}

function getRelativeRect(idxs) {
  return idxs.map((item) => (item >= 2 ? item - 2 : item + 2));
}
// 返回矩形和正多边形的相对点 （一一枚举出来）
function getRelativeIdx(idxs, geoType: string) {
  if (geoType === 'Rect') {
    const indexs = getRelativeRect(idxs);
    return indexs;
  } else if (geoType.includes('Polygon')) {
    const count = Number(geoType.replace('Polygon-', ''));
    const resIdxs = [];
    const num = Math.ceil(count / 2 - 1);
    for (let i = 0; i < count; i++) {
      const ind = i === count - 1 ? 0 : i + 1;
      let ind2 = i === count - 1 ? num - 1 : i + num;
      if (ind2 > count - 1) {
        ind2 = ind2 - count;
      }
      if (!idxs.includes(i) || !idxs.includes(ind)) {
        resIdxs.push([i, ind]);
      }
      if (!idxs.includes(i) || !idxs.includes(ind2)) {
        resIdxs.push([i, ind2]);
      }
    }
    return resIdxs;
  }
  return [];
}
// 根据点的id获取组的id和index
function getGroupsByPointIds(ids: string[]) {
  const groupidsMap: Record<string, [number, string][]> = {};
  const pointIds: { [key: string]: string[] } = {};
  ids?.forEach((id) => {
    const curve = dimRender().getSketMap().get(id);
    const group = curve?.['groups'];
    if (curve?.type === 'Line') {
      pointIds[id] = curve.relative.slice(0, 2);
    }
    if (group?.length > 0) {
      group.forEach((item) => {
        if (!groupidsMap[item.groupid]) {
          groupidsMap[item.groupid] = [[item.idx, item.type]];
        } else {
          groupidsMap[item.groupid].push([item.idx, item.type]);
        }
      });
    }
  });
  for (const key in groupidsMap) {
    if (groupidsMap[key].length < 2) {
      delete groupidsMap[key];
    }
  }
  return {
    groupidsMap,
    pointIds,
  };
}

// 检测矩形是否有固定、横向、竖直约束
function checkRectFixed(curveId, extra = null) {
  const curves = dimRender().getSketMap();
  const groups = curves.get(curveId)?.groups?.[0];
  let isFixed = false;
  if (groups?.type === 'Rect') {
    curves.forEach((item) => {
      if (item.type === 'Line') {
        const flag = item?.groups.some(
          (group) => groups.groupid === group.groupid,
        );
        if (
          flag &&
          item.constraints.some((cons) =>
            [...fixCons, extra].includes(cons.type),
          )
        ) {
          isFixed = true;
        }
      }
    });
  }
  return isFixed;
}
